package com.lagou.filter;

import com.alibaba.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * dubbo性能监控
 *
 * @author
 */
@Activate(
        group = {"provider"}
)
public class DubboPerformanceFilter implements Filter {
    /**
     * 各个方法耗时统计
     */
    private static Map<String, List<Long>> costTimeMap = new ConcurrentHashMap<>();


    private static ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);

    static {
        executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                if (costTimeMap.isEmpty()) {
                    System.out.println("近5秒内所有方法都没有被访问");
                }
                for (Map.Entry<String, List<Long>> entry : costTimeMap.entrySet()) {
                    List<Long> list = entry.getValue();
                    if (CollectionUtils.isEmpty(list)) {
                        System.out.println("方法" + entry.getKey() + "没有被访问");
                        continue;
                    }
                    Collections.sort(list);
                    int position90 = list.size() * 90 / 100;
                    int position99 = list.size() * 99 / 100;
                    Long tp90 = list.get(position90);
                    Long tp99 = list.get(position99);
                    System.out.println("方法" + entry.getKey() + "5秒内被访问" + list.size() + "次");
                    System.out.println("方法" + entry.getKey() + "tp90=" + tp90 + "毫秒");
                    System.out.println("方法" + entry.getKey() + "tp99=" + tp99 + "毫秒");
                    list.clear();
                }
                System.out.println();
            }
        }, 5, 5, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long startTime = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        long costTime = System.currentTimeMillis() - startTime;
        String methodName = invocation.getMethodName();
        if (costTimeMap.get(methodName) == null) {
            costTimeMap.put(methodName, Collections.synchronizedList(new ArrayList<Long>()));
        }
        List list = costTimeMap.get(methodName);
        list.add(costTime);
        return result;
    }
}
